package weeny.delaunay.pre;

import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import prefuse.data.Graph;
import prefuse.data.Node;
import weeny.pre.util.Geom;
import weeny.pre.util.Pre;

/**
 * This class is designed to process {@link prefuse.data.Graph}. Basically, you
 * need to call {@link #reDelaunay(Graph)} function. This function will remove
 * every edge in the input graph, and return a collection of triplets indicating
 * all triangles in the mesh.
 * 
 * @author weeny
 */
public class DelaunayUtil extends weeny.delaunay.DelaunayUtil{
	private Point2D temp = new Point2D.Double();
	@Override
	protected Point2D asPnt(Object obj) {
		return Geom.dumpPnt(obj, temp);
	}
	
	/**
	 * Perform a delaunay triangulation on input graph nodes. Nothing is changed
	 * in the input graph.
	 * 
	 * @param graph
	 * @return a collection of triplets indicating the resulting triangle mesh
	 */
	public Set<List<Node>> triangles(Graph graph){
		Set<Set> triSet = delaunay(graph.nodes());
		if (triSet == null) {
			throw new IllegalStateException("triangle set is null!");
		}
		Set<List<Node>> resultTris = new HashSet<List<Node>>();
		for (Set set : triSet) {
			List<Node> list = new ArrayList<Node>(3);
			list.addAll(set);
			resultTris.add(list);
		}
		return resultTris;
	}
	/**
	 * Note: this function will clear all edges in the input graph, re-connect
	 * all the nodes to generate a triangle mesh.
	 * 
	 * @param graph
	 * @return a collection of triplets indicating the resulting triangle mesh
	 */
	public Set<List<Node>> reDelaunay(Graph graph){
		Set<List<Node>> resultTris = triangles(graph);		
		graph.getEdgeTable().clear();
		for (List<Node> list : resultTris) {
			for(int idx = 0; idx<3; idx++){
				//each triangle edge is usually shared by two triangles,
				//if it is not null, it means that this two nodes are already 
				//been connected when processing some other triangle
				if (Pre.edge(list.get(idx), list.get((idx+1)%3)) == null) {
					graph.addEdge(list.get(idx), list.get((idx+1)%3));	
				}
			}
		}
		return resultTris;
	}
}